﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FarseerGames.FarseerPhysics;
using Microsoft.Xna.Framework.Graphics;
using FarseerGames.FarseerPhysics.Dynamics;
using FarseerGames.FarseerPhysics.Collisions;
using FarseerGames.FarseerPhysics.Factories;
using FarseerGames.FarseerPhysics.Controllers;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Net;


namespace GrapplingHookGameData
{
    public class Grenade:PhysicsObject
    {
        #region Fields
        public int Timer {get; set;}

        public enum GrenadeState { INACTIVE, TICKING, EXPLODING };
        private GrenadeState currentState = GrenadeState.INACTIVE;
        private  GrenadeState previousState = GrenadeState.INACTIVE;
        public GrenadeState CurrentState
        {
            get { return currentState; }
            private set { previousState = currentState; currentState = value; }
        }

        //used to track time in explotion state
        private int explotionTime = 0;

        private Player player;
        #endregion

        #region Initialization
        public Grenade(IGameDataCallbacks gameCallback, Vector2 startPosition, Player owner)
            : base(gameCallback, startPosition, 25, 42, "grenade/grenade", false)
        {
            this.player = owner;
        }

        public override void LoadContent(ContentManager content, PhysicsSimulator physicsSimulator)
        {
            base.LoadContent(content, physicsSimulator);

            Body = BodyFactory.Instance.CreateEllipseBody(physicsSimulator, Width / 2, Height / 2, Constants.GRENADE_MASS);
            Geom = GeomFactory.Instance.CreateEllipseGeom(physicsSimulator, Body, Width/2, Height/2, 8);
            Geom.RestitutionCoefficient = 0.4f;

            Geom.OnCollision += new Geom.CollisionEventHandler(gameCallback.onGrenadeCollision);
            Geom.Tag = this;

            Body.Position = position;
            Extinguish();
        }
        #endregion



        #region Update

        public override void Update(GameTime gameTime, bool isHost)
        {
            base.Update(gameTime, isHost);

            //only hosts updates grenade states, clients just draw based on data sent from host
            if (isHost)
            {
                switch (CurrentState)
                {
                    case GrenadeState.INACTIVE:
                        break;
                    case GrenadeState.TICKING:
                        UpdateTicking(gameTime);
                        break;
                    case GrenadeState.EXPLODING:
                        UpdateExploding(gameTime);
                        break;
                }
            }
                //client must still detect explotions to draw particles
            else
            {
                if (CurrentState == GrenadeState.EXPLODING && previousState == GrenadeState.TICKING)
                {
                    previousState = GrenadeState.EXPLODING; //make sure this only happens once
                    ExplodeGrenade();
                }
            }
        }

        private void UpdateTicking(GameTime gameTime)
        {
            Timer -= gameTime.ElapsedGameTime.Milliseconds;
            if (Timer < 0)
            {
                ExplodeGrenade();
            }
        }

        private void UpdateExploding(GameTime gameTime)
        {
            explotionTime += gameTime.ElapsedGameTime.Milliseconds;
            if (explotionTime > Constants.GRENADE_EXPLOSION_TIME_MS)
            {
                Extinguish();
            }
        }
        #endregion

        #region Actions / State Change
        public void Activate()
        {
            CurrentState = GrenadeState.TICKING;
            Timer = Constants.GRENADE_TIMER_MS;
            Body.Enabled = true;
            explotionTime = 0;
        }

        public void Extinguish()
        {
            CurrentState = GrenadeState.INACTIVE;
            Body.ResetDynamics();
            Body.Enabled = false;
        }

        public void ExplodeGrenade()
        {
            CurrentState = GrenadeState.EXPLODING;
            Body.Enabled = false;
            gameCallback.GrenadeExploded(this);
        }

        #endregion

        #region Draw
        public override void Draw(SpriteBatch spriteBatch)
        {
            //explotions are drawn by particles
            if (CurrentState != GrenadeState.INACTIVE && CurrentState != GrenadeState.EXPLODING)
            {
                base.Draw(spriteBatch);
            }
        }
        #endregion

        #region Networking
        /// <summary>
        /// Writes the data that is needed by clients to draw this grenade
        /// </summary>
        /// <param name="packetWriter"></param>
        public void WriteDataToClients(PacketWriter packetWriter)
        {
            packetWriter.Write(Position);
            packetWriter.Write(Rotation);
            packetWriter.Write((int)CurrentState);
        }

        /// <summary>
        /// Read the data that is needed by clients to draw this grenade
        /// </summary>
        /// <param name="packetWriter"></param>
        public void ReadDataFromHost(PacketReader packetReader)
        {
            //clients set the position directly
            Position = packetReader.ReadVector2();
            Rotation = packetReader.ReadSingle();
            CurrentState = (GrenadeState)packetReader.ReadInt32();

      //      if (currentState == GrenadeState.TICKING) System.Diagnostics.Debugger.Break();
        }
        #endregion

    }
}
